﻿using System;
using System.IO;
using System.Web;
using System.Web.Mvc;
using Supermodel.DomainModel;
using Supermodel.Exceptions;
using Supermodel.MVC.Extensions;

namespace Supermodel.MVC.FormModels
{
    public class BinaryFileFormModel : IComparable, IFormModelModelBinder, IFormModelEditorTemplate, IFormModelEntityMapper
    {
        public void Empty()
        {
            Name = null;
            BinaryContent = null;
        }
        
        public string Name { get; set; }
        public byte[] BinaryContent { get; set; }
        public bool IsEmpty
        {
            get { return string.IsNullOrEmpty(Name) && (BinaryContent == null || BinaryContent.Length == 0); }
        }

        public int CompareTo(object obj)
        {
            var typedObj = (BinaryFileFormModel)obj;
            if (Name == null) return 0; //if we are an empty object, we say it equals b/c then we do not override db value
            int result = Name.CompareTo(typedObj.Name);
            if (result != 0) return result;
            return BinaryContent.GetHashCode().CompareTo(typedObj.GetHashCode());
        }

        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            if (controllerContext == null) throw new ArgumentNullException("controllerContext");
            if (bindingContext == null) throw new ArgumentNullException("bindingContext");

            HttpPostedFileBase rawFile = controllerContext.HttpContext.Request.Files[bindingContext.ModelName/* + ".Upload"*/];

            var file = new BinaryFileFormModel();
            if (rawFile == null || rawFile.ContentLength == 0 || string.IsNullOrEmpty(rawFile.FileName))
            {
                var originalValue = (BinaryFileFormModel)bindingContext.Model;
                if (originalValue.IsEmpty)
                {
                    file.Name = null;
                    file.BinaryContent = null;
                    if (bindingContext.ModelMetadata.IsRequired) bindingContext.ModelState.AddModelError(bindingContext.ModelName, string.Format("The field {0} is required", bindingContext.ModelMetadata.DisplayName ?? bindingContext.ModelMetadata.PropertyName));
                }
                else
                {
                    file = originalValue;
                }
            }
            else
            {
                file.Name = Path.GetFileName(rawFile.FileName);
                file.BinaryContent = new byte[rawFile.ContentLength];
                rawFile.InputStream.Read(file.BinaryContent, 0, rawFile.ContentLength);
            }
            return file;
        }

        public bool GetIEditorTemplateImplemented() { return true; }
        public MvcHtmlString EditorTemplate(HtmlHelper html)
        {
            return html.BinaryFileFormModelEditor();
        }

        public void MapFromEntityObject(object obj, Type objType)
        {
            if (objType != typeof(BinaryFile)) throw new FormModelPropertyCantBeAutomapedException(string.Format("{0} can't be automapped to {1}", GetType().Name, objType.Name));

            var binaryFileObj = (BinaryFile)obj;
            Name = (binaryFileObj == null) ? "" : binaryFileObj.Name;
            BinaryContent = (binaryFileObj == null) ? new byte[0] : binaryFileObj.BinaryContent;
        }

        public object MapToEntityObject(object obj, Type objType)
        {
            if (objType != typeof(BinaryFile)) throw new FormModelPropertyCantBeAutomapedException(string.Format("{0} can't be automapped to {1}", GetType().Name, objType.Name));

            var binaryFileObject = new BinaryFile { Name = Name, BinaryContent = BinaryContent };
            return binaryFileObject;
        }
    }
}
